package com.yunhai.ucenter.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yunhai.common.dto.GlobalException;
import com.yunhai.common.dto.PaginationVo;
import com.yunhai.common.dto.UserHolderDto;
import com.yunhai.common.utils.*;
import com.yunhai.model.entity.tms.TmsStoreEntity;
import com.yunhai.model.entity.ums.*;
import com.yunhai.model.vo.ums.*;
import com.yunhai.ucenter.entity.vo.SysUserVo;
import com.yunhai.ucenter.mapper.*;
import com.yunhai.ucenter.service.CaptchaService;
import com.yunhai.ucenter.service.SysUserService;
import com.yunhai.ucenter.service.UserRedisService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 用户表 服务实现类
 * </p>
 *
 * @author mengze
 * @since 2023-08-23
 */
@Service
@Slf4j
public class SysUserServiceImpl implements SysUserService {

    @Resource
    private SysUserMapper sysUserMapper;
    @Resource
    private SysRoleMapper sysRoleMapper;
    @Resource
    private AuthenticationManager authenticationManager;
    @Resource
    private SysUserRoleMapper sysUserRoleMapper;
    @Resource
    private SysRoleMenuMapper sysRoleMenuMapper;
    @Resource
    private SysMenuMapper sysMenuMapper;
    @Resource
    private CaptchaService captchaService;
    @Resource
    private UserRedisService userRedisService;

    @Resource
    private StoreMapper storeMapper;

    /**
     * 手机号是否注册
     * */
    @Override
    public Boolean isPhoneRegistered(String phoneNumber) throws Exception {

        LambdaQueryWrapper<UmsUser> lqs = new LambdaQueryWrapper<>();
        lqs.eq( UmsUser::getUserName, phoneNumber );
        List<UmsUser> umsUsers = sysUserMapper.selectList(lqs);
        return umsUsers != null;
    }

    @Transactional
    public void addUser( UmsUserVo umsUserVo ) throws Exception {

        if(  ObjectUtil.isNull(umsUserVo.getUserName()) ){
            throw GlobalException.gen(10001, "请传入用户名userName");
        }

        synchronized ( umsUserVo.getUserName().intern() ){
            //1、检查账号是否存在
            UmsUser existUser = sysUserMapper.getAllStatusUser(umsUserVo.getUserName());
            if( existUser != null ){
                throw GlobalException.gen(10001, "用户已存在");
            }

            //查找角色是否存在
            if(!ObjectUtil.isNotEmptyList(umsUserVo.getRoleIdList()) ){
                throw GlobalException.gen(10001, "需要设置用户角色");
            }

            UmsUser sysUser = new UmsUser();
            ReflectionCopy.copyProperties(sysUser, umsUserVo);
            sysUserMapper.insert(sysUser);
            for( Long roleId : umsUserVo.getRoleIdList() ){
                UmsUserRole sysUserRole = new UmsUserRole();
                sysUserRole.setUserId(sysUser.getId());
                sysUserRole.setRoleId(roleId);
                sysUserRoleMapper.insert( sysUserRole );
            }
        }
        return;
    }

    @Transactional
    public void updateUser( UmsUserVo userVo) throws Exception {

         userVo.setUserName(null);
        //先移除之前的 roleId 与 userId 对应的关系

        //如果没有传用户角色id过来，就认为不进行角色修改。
        if( ObjectUtil.isNotEmptyList(userVo.getRoleIdList())  ){
            LambdaQueryWrapper<UmsUserRole> deleteLqs = new LambdaQueryWrapper();
            deleteLqs.eq( UmsUserRole::getUserId, userVo.getId() );
            sysUserRoleMapper.delete(deleteLqs);

            //新增新的角色
            for( Long roleId : userVo.getRoleIdList() ){
                UmsUserRole sysUserRole = new UmsUserRole();
                sysUserRole.setUserId(userVo.getId());
                sysUserRole.setRoleId(roleId);
                sysUserRoleMapper.insert( sysUserRole );
            }
        }

        if( userVo.getId() == null ){
            throw GlobalException.gen(10001, "用户不存在");
        }

        UmsUser sysUser = new UmsUser();
        ReflectionCopy.copyProperties(sysUser, userVo);
        sysUserMapper.updateById(sysUser);
        return;
    }

    @Override
    public void batchRemoveUser(List<Long> ids) throws Exception {

        sysUserMapper.deleteBatchIds(ids);
        return;
    }

    @Override
    public IPage paginationUserList(PaginationVo paginationVo, SysUserVo sysUserVo) throws Exception {

        //如果 roleId 存在，则先通过roleId 查询
        List<Long> userIdsFromRole = null;
        if( sysUserVo.getRoleId() != null ){
            LambdaQueryWrapper<UmsUserRole> lqs = new LambdaQueryWrapper<>();
            lqs.eq(UmsUserRole::getRoleId, sysUserVo.getRoleId());
            List<UmsUserRole> sysUserRoles = sysUserRoleMapper.selectList(lqs);
            userIdsFromRole = sysUserRoles.stream().map( item->item.getUserId() ).collect(Collectors.toList());
        }

        //根绝角色id，没有找到一个用户。
        if( sysUserVo.getRoleId() != null && !ObjectUtil.isNotEmptyList(userIdsFromRole) ){
            return  new Page(paginationVo.getPageIndex(), paginationVo.getPageSize());
        }

        IPage page = new Page(paginationVo.getPageIndex(), paginationVo.getPageSize());
        LambdaQueryWrapper<UmsUser> lambdaQueryWrapper = new LambdaQueryWrapper();
        lambdaQueryWrapper.likeRight(  sysUserVo.getUserName()!=null,
                UmsUser::getUserName, sysUserVo.getUserName() );
        lambdaQueryWrapper.likeRight(  sysUserVo.getNickname()!=null,
                UmsUser::getNickName, sysUserVo.getNickname() );
        lambdaQueryWrapper.in( ObjectUtil.isNotEmptyList(userIdsFromRole),  UmsUser::getId, userIdsFromRole );
        lambdaQueryWrapper.orderByDesc(UmsUser::getCreateTime);

        sysUserMapper.selectPage(page, lambdaQueryWrapper);
        List<UmsUser> records = page.getRecords();
        if( records.size() == 0 ){
            return page;
        }
        List<Long> userIds = records.stream().map(item->item.getId()).collect(Collectors.toList());
        LambdaQueryWrapper<UmsUserRole> userRoleLqs = new LambdaQueryWrapper();
        userRoleLqs.in( UmsUserRole::getUserId, userIds );
        List<UmsUserRole> sysUserRoles = sysUserRoleMapper.selectList(userRoleLqs);
        //没有角色需要查询
        if( sysUserRoles.size() == 0 ){
            return page;
        }

        Set<Long> roleIdSet  = sysUserRoles.stream().map(item->item.getRoleId()).collect(Collectors.toSet());
        List<UmsRole> sysRoles = sysRoleMapper.selectBatchIds(roleIdSet);

        for( UmsUser record: records ){
            List<Long> roleIds = sysUserRoles.stream().filter(item->item.getUserId().equals(record.getId())).map( item->item.getRoleId() ).collect(Collectors.toList());
            record.setRoleIdList( roleIds );

            List<UmsRole> rolelist = new ArrayList();
            for( Long roleId : roleIds ){
                List<UmsRole> filterRoles = sysRoles.stream().filter(item -> {
                    return item.getId().equals(roleId);
                }).collect(Collectors.toList());
                rolelist.addAll(filterRoles);
            }
            record.setRoleList(rolelist);
        }
        page.setRecords(records);
        return page;
    }


    @Override
    public List<UmsUser> allUserList() throws Exception {
        List<UmsUser> sysUsers = sysUserMapper.selectList(null);
        return sysUsers;
    }

    public UmsUser getUserInfoByUsername( String username ) throws Exception {

        //查询用户
        LambdaQueryWrapper<UmsUser> lambdaQueryWrapper = new LambdaQueryWrapper();
        lambdaQueryWrapper.eq(UmsUser::getUserName, username );
        UmsUser userInfoDto = sysUserMapper.selectOne(lambdaQueryWrapper);
        if( userInfoDto == null ){
            throw GlobalException.gen(10001, "用户不存在");
        }

        Long userId = userInfoDto.getId();
        LambdaQueryWrapper<TmsStoreEntity> storeLqs = new LambdaQueryWrapper<>();
        storeLqs.eq( TmsStoreEntity::getUserId,  userId);
        List<TmsStoreEntity> storeList = storeMapper.selectList(storeLqs);
        userInfoDto.setStoreList(storeList);

        return  userInfoDto;
    }


    public UserInfoVo loginByUsername(AccountPasswordVo loginVo) throws Exception {

        UmsUser userInfoDto = getUserInfoByUsername(loginVo.getUserName());
        if( userInfoDto == null ){
            throw GlobalException.gen(10001, "用户不存在");
        }

        /**
         * 开始认证
         */
        //1、将前端传过来的 User 封装成 springsecurity 能识别的对象
        String password = MD5Util.encryptMD5( loginVo.getPassword() +userInfoDto.getSalt());
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken( loginVo.getUserName(), password );
        //2、开始认证
        Authentication authentication = authenticationManager.authenticate(authenticationToken);
        //3、处理认证结果
        if( Objects.isNull(authentication) ){
            throw GlobalException.gen(10002,"用户名或密码错误");
        }

        //4、使用 userId 生成 jwt
        String jwt = JwtUtils.createJWT("" + userInfoDto.getId());
        log.info("login: " + userInfoDto.getUserName() + ", "+jwt);


        //5、redis存储用户信息
        userRedisService.saveUser(userInfoDto);

        //7、将 token, userInfo 返回给客户端
        return new UserInfoVo( jwt,JwtUtils.JWT_TTL+new Date().getTime(),userInfoDto );
    }


    @Override
    public void updateUserPassword(UmsUser sysUser) throws Exception {

         UmsUser newSysUser = new UmsUser();
         //只允许修改密码
         newSysUser.setId(sysUser.getId())
            .setPassword(sysUser.getPassword());
         sysUserMapper.updateById(newSysUser);
         return;
    }


    @Override
    public List<UmsUser> getUserListByIds( List<Long> userIds ) throws Exception {
        return sysUserMapper.selectBatchIds(userIds);
    }

    public UmsUser getUserByOpenId(String openId) throws Exception {

        LambdaQueryWrapper<UmsUser> lambdaQueryWrapper = new LambdaQueryWrapper();
        lambdaQueryWrapper.eq( UmsUser::getOpenid, openId );
        UmsUser sysUser = sysUserMapper.selectOne(lambdaQueryWrapper);
        return sysUser;
    }

    public List<UmsPermission> curUserPermissionList() throws Exception {

        UserHolderDto user = UserHolder.getUser();
        Long userId = user.getId();

        LambdaQueryWrapper<UmsUserRole> userRoleLqs = new LambdaQueryWrapper();
        userRoleLqs.eq( UmsUserRole::getUserId, userId );
        //获取当前用户的角色列表
        List<UmsUserRole> sysUserRoles = sysUserRoleMapper.selectList(userRoleLqs);
        if( sysUserRoles == null || sysUserRoles.size() == 0 ){
            return new ArrayList<UmsPermission>();
        }
        //获取当前用户下所有的角色id
        List<Long> roleIds = sysUserRoles.stream().map(item->{
            return item.getRoleId();
        }).collect(Collectors.toList());
        //获取角色id下的所有权限id
        LambdaQueryWrapper<UmsRolePermission> roleMenuLqs = new LambdaQueryWrapper();
        roleMenuLqs.in( UmsRolePermission::getRoleId, roleIds );
        List<UmsRolePermission> sysRoleMenus = sysRoleMenuMapper.selectList(roleMenuLqs);
        if( sysRoleMenus == null || sysRoleMenus.size() == 0 ){
            return new ArrayList<UmsPermission>();
        }
        //获取菜单id下所有数据
        Set<Long> ids = sysRoleMenus.stream().map( item-> {
            return item.getMenuId();
        }).collect(Collectors.toSet());
        LambdaQueryWrapper<UmsPermission> menuLqs = new LambdaQueryWrapper<>();
        menuLqs.in( UmsPermission::getId, ids );
        List<UmsPermission> sysMenus = sysMenuMapper.selectList(menuLqs);

        return sysMenus;
    }

    public Integer getMonthCountOfUser() throws Exception {

        //获取本月第一天的日期。
        LocalDate currentDate = LocalDate.now();
        LocalDate firstDayOfMonth = currentDate.withDayOfMonth(1);

        LambdaQueryWrapper<UmsUser> userInfoLqs = new LambdaQueryWrapper();
        userInfoLqs.ge( UmsUser::getCreateTime, firstDayOfMonth );
        Integer monthCountOfUser = sysUserMapper.selectCount(userInfoLqs);
        return monthCountOfUser;
    }

    @Override
    public UmsUser getUserInfo(Long id) throws Exception {
        return sysUserMapper.selectById(id);
    }

    @Override
    public void resetPassword(ResetPasswordVo resetPasswordVo) throws Exception {

        // 检查手机号是否已注册
        if (!isPhoneRegistered(resetPasswordVo.getUserName())) {
            throw new RuntimeException("该手机号未注册");
        }

        Boolean available = captchaService.verifyCaptcha(resetPasswordVo.getUserName(),
                resetPasswordVo.getCode());
       if( !available ){
           throw GlobalException.gen(10012, "验证码已过期");
       }

       //根据手机号码，获取到手机号码
        LambdaQueryWrapper<UmsUser> lqs = new LambdaQueryWrapper<>();
        lqs.eq( UmsUser::getUserName, resetPasswordVo.getUserName() );
        UmsUser user = sysUserMapper.selectOne(lqs);
        if( user == null ){
            throw GlobalException.gen(10003, "用户不存在");
        }

        String password = MD5Util.encryptMD5( resetPasswordVo.getPassword() +user.getSalt());
        UmsUser newUser = new UmsUser();
        newUser.setId( user.getId() );
        newUser.setPassword(password);
        sysUserMapper.updateById(newUser);

    }


    /**
     * 获取验证码
     * */
    @Override
    public String  getValidateCode(String phoneNumber) throws Exception {

        // 检查手机号是否已注册
        if (!isPhoneRegistered( phoneNumber )) {
            throw new RuntimeException("该手机号未注册");
        }

       return  captchaService.generateAndSendCaptcha(phoneNumber);
    }


    /**
     *  移除账号
     * */
    @Override
    public void removeAccount(AccountRemoveVo accountRemoveVo) throws Exception {

       boolean isExists = captchaService.verifyCaptcha(accountRemoveVo.getUserName(), accountRemoveVo.getCode());
       if( !isExists ){
            throw GlobalException.gen(10003, "验证码已过期");
       }

       Long userId = UserHolder.getUser().getId();
       LambdaQueryWrapper<UmsUser>  lqs = new LambdaQueryWrapper<>();
       lqs.eq( UmsUser::getUserName, accountRemoveVo.getUserName() );
       lqs.eq( UmsUser::getId, userId );
        sysUserMapper.delete(lqs);

    }
}
